package com.bestv.search.management.datasyn.spider;

import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.Info;
import com.bestv.search.common.model.Person;
import com.bestv.search.common.model.PersonProduct;
import com.bestv.search.common.service.InfoManager;
import com.bestv.search.common.service.PersonManager;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.management.datasyn.spider.model.YouKuPersonJSON;
import org.hibernate.Hibernate;

import java.util.*;

public class SpiderPersonSyncer extends SpiderSyncer {

    private PersonManager personManager;
    private InfoManager infoManager;
    private Map<String, Long[]> productInfoMap = new HashMap<String, Long[]>();

    public SpiderPersonSyncer() {
        super();
        personManager = (PersonManager) context.getBean("personManager");
        infoManager = (InfoManager) context.getBean("infoManager");
    }

    public void sync() {
        String syncMessage = null;
        try {
            status = getProgramSyncStatus(StringConst.YOUKU, 1, StringConst.PERSON);
            Date syncSuccessDate = null;
            if (status != null) {
                syncSuccessDate = status.getSyncSuccessTime();
            }

            // Gets file path
            String filePath = getFileFullPath(StringConst.PERSON, StringConst.YOUKU, syncSuccessDate,
                    StringConst.ALL_PERSONS_FILE);
            if (filePath != null) {
                YouKuPersonJSON personJSON = new YouKuPersonJSON();
                Person personInDB = new Person();
                sync(personInDB, personJSON, filePath);
                syncMessage = "Success sync persons from system search_spider @" + new Date();
            } else {
                syncMessage = "Doesn't find any new persons in system search_spider @" + new Date();
            }
        } catch (Exception e) {
            syncMessage = "Failed sync persons from system search_spider @" + new Date();
            logger.error(syncMessage);
            logger.error(e);
        } finally {
            // Updates sync status
            updateSyncStatus(getSyncStatus(StringConst.YOUKU, StringConst.PERSON, syncMessage));
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    protected <T, K> T convert(K sourceObject, T destObject) {
        if (sourceObject != null) {
            YouKuPersonJSON personJSON = (YouKuPersonJSON) sourceObject;
            Person personInDB = new Person();
            try {
                personInDB.setId(Long.valueOf(Math.abs(personJSON.getName().hashCode()) + StringConst.EMPTY
                        + Math.abs(personJSON.getPersonId().hashCode())));
            } catch (NumberFormatException e) {
                try {
                    personInDB.setId(Long.valueOf(personJSON.getPersonId()));
                } catch (NumberFormatException ex) {
                    personInDB.setId(Long.valueOf(personJSON.getPersonId().hashCode()));
                }
            }
            personInDB.setPersonId(personJSON.getPersonId());
            personInDB.setName(personJSON.getName());
            if (personJSON.getAvatar_youku() != null) {
                personInDB.setAvatar_youku(Hibernate.createBlob(personJSON.getAvatar_youku()));
            }
            if (personJSON.getAvatar_iqiyi() != null) {
                personInDB.setAvatar_iqiyi(Hibernate.createBlob(personJSON.getAvatar_iqiyi()));
            }
            personInDB.setGender(personJSON.getGender());
            personInDB.setNationality(personJSON.getNationality());
            personInDB.setBloodtype(personJSON.getBloodtype());
            personInDB.setHeight(personJSON.getHeight());
            personInDB.setOccupation(personJSON.getOccupation());
            personInDB.setConstellation(personJSON.getConstellation());
            personInDB.setBirthday(personJSON.getBirthday());
            personInDB.setHomeplace(personJSON.getHomeplace());
            personInDB.setAlias(Arrays.toString(personJSON.getAlias()));
            personInDB.setDescription(personJSON.getDescription());
            personInDB.setUpdateTime(new Date());
            personInDB.setHonor(personJSON.getHonor());
            personInDB.setSource(personJSON.getSource());
            Set<PersonProduct> products = new HashSet<PersonProduct>();
            for (PersonProduct product : personJSON.getProducts()) {
                products.add(product);
            }
            personInDB.setProducts(products);
            return (T) personInDB;
        } else {
            return null;
        }
    }

    @Override
    protected <T, K> void saveOrUpdateToDB(K sourceObj, List<T> dbObj) {
        // local site code equals to local data source Key.
        String siteCode = systemCache.getLocalDataSourceKey();
        DataSourceKey key = DataSourceKeyUtil.convert(siteCode);

        @SuppressWarnings("unchecked")
        List<Person> list = (List<Person>) dbObj;

        List<Map.Entry<String, Long>> mapping = new ArrayList<Map.Entry<String, Long>>();
        for (Person person : list) {
            Set<PersonProduct> products = person.getProducts();
            for (PersonProduct product : products) {
                String id = product.getPersonId() + Math.abs(product.getName().hashCode())
                        + Math.abs(product.getCategory().hashCode()) + product.getYear();
                product.setId(id);
                product.setUpdateTime(new Date());

                // Gets infos by names
                if (product.getCategory() != null
                        && (product.getCategory().equals(StringConst.MOVIE_CHINESE) || product.getCategory().equals(
                        StringConst.TV_CHINESE))) {
                    String keyInMap = String.valueOf(Math.abs(product.getName().hashCode()))
                            + Math.abs(product.getCategory().hashCode());

                    if (productInfoMap.containsKey(keyInMap)) {
                        Long[] infoIds = productInfoMap.get(keyInMap);
                        for (long infoId : infoIds) {
                            mapping.add(new AbstractMap.SimpleEntry<String, Long>(id, infoId));
                        }
                    } else {
                        List<Info> infos = infoManager.getInfoByName(key, new String[]{product.getName()},
                                product.getCategory());
                        if (infos != null && infos.size() > 0) {
                            Long[] infoIds = new Long[infos.size()];
                            int i = 0;
                            for (Info info : infos) {
                                mapping.add(new AbstractMap.SimpleEntry<String, Long>(id, info.getId()));
                                infoIds[i] = info.getId();
                                i++;
                            }
                            productInfoMap.put(keyInMap, infoIds);
                        } else {
                            productInfoMap.put(keyInMap, new Long[0]);
                        }
                    }
                }
            }
        }

        personManager.saveOrUpdate(key, list);

        personManager.saveProductInfoReferenceList(key, mapping);
    }
}